﻿using System.Collections.Generic;
using Microsoft.Xna.Framework;
using ShevaEngine.Core.Foundation.Emitters;
using ShevaEngine.Core.Foundation.GraphicsObjects;
using ShevaEngine.Core.Interfaces;
using ShevaEngine.Core.Modules.Materials;

namespace ShevaEngine.Core.Modules.ParticleSystems
{
    /// <summary>
    /// Particle systems manager.
    /// </summary>
    public class ParticleSystemManager : IUpdateAble
    {
        /// <summary>Singleton.</summary>
        public readonly static ParticleSystemManager Instance = new ParticleSystemManager();

        /// <summary>Particle systems.</summary>
        public List<ParticleSystem> ParticleSystems;

        /// <summary>
        /// Constructor.
        /// </summary>
        public ParticleSystemManager()
        {
            this.ParticleSystems = new List<ParticleSystem>();
        }

        /// <summary>
        /// Method Update.
        /// </summary>
        /// <param name="time"></param>
        public void Update(GameTime time)
        {
            for (int i = this.ParticleSystems.Count - 1; i >= 0; i--)
                this.ParticleSystems[i].Update(time);
        }


        /// <summary>
        /// Method creates particle system.
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        public ParticleSystem CreateParticleSystem(string name)
        {
            ParticleSystemSettings settings = ShevaEngine.Instance.Content.Load<ParticleSystemSettings>("ParticleSystems\\" + name);

            ParticleSystem output = new ParticleSystem();

            switch (settings.ParticleType)
            {
                case ParticleType.RectangleBillboardParticle:
                    output.DrawCall = Drawing.Instance.CreateRectangleTextured();
                    break;
                default:
                    break;
            }

            output.DrawCallKey = output.DrawCallKey.Clone();

            output.DrawCallKey.MaterialID = MaterialManager.Instance.GetMaterialID(settings.MaterialName);
            output.DrawCallKey.TextureState = TextureManager.Instance.GetTextureStateId(
                new Textures(settings.Textures));

            GraphicsMaterial material = MaterialManager.Instance[output.DrawCallKey.MaterialID].GraphicsProfile;

            GraphicsMaterialParametersList graphicsParameters = new GraphicsMaterialParametersList();

            output.TimeParam = new GraphicsMaterialParameterFloat("Time", 0.0f);
            graphicsParameters.Add(output.TimeParam);

            output.DurationParam = new GraphicsMaterialParameterFloat("Duration", settings.Duration);
            graphicsParameters.Add(output.DurationParam);

            output.StartSize = new GraphicsMaterialParameterVector2("StartSize", settings.ParticleStartSize);
            graphicsParameters.Add(output.StartSize);

            output.EndSize = new GraphicsMaterialParameterVector2("EndSize", settings.ParticleEndSize);
            graphicsParameters.Add(output.EndSize);

            output.StartVelocity = new GraphicsMaterialParameterVector3("StartVelocity", settings.ParticleStartVelocity);
            graphicsParameters.Add(output.StartVelocity);

            output.EndVelocity = new GraphicsMaterialParameterVector3("EndVelocity", settings.ParticleEndVelocity);
            graphicsParameters.Add(output.EndVelocity);

            output.Gravity = new GraphicsMaterialParameterVector3("Gravity", settings.Gravity);
            graphicsParameters.Add(output.Gravity);

            output.DurationParam = new GraphicsMaterialParameterFloat("Duration", settings.Duration);
            graphicsParameters.Add(output.DurationParam);            

            output.DrawCallKey.MaterialParamsID = material.GetMaterialParametersId(graphicsParameters);

            switch (settings.Emitter)
            {
                case "PointEmitter":
                    output.Emitter = new PointEmitter();
                    (output.Emitter as PointEmitter).Radius = settings.EmitterRadius;
                    break;
                default:
                    break;
            }

            output.ParticlesCount = settings.ParticlesCount;
            output.WorldMatrices = new Matrix[settings.ParticlesCount];

            for (int i = settings.ParticlesCount - 1; i >= 0; i--)
                output.WorldMatrices[i] = output.SetupMatrix(0);

            this.ParticleSystems.Add(output);

            return output;
        }
    }
}
